﻿/* 2012/10/4 */
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing;

namespace Cosmos.Windows.Forms
{
    /// <summary>
    /// Represents a tab control which can be split.
    /// </summary>
    partial class SplitTabControl : TabControl
    {
        private int _clickedIndex;
        private TabPage _clickdTab;
        private TabControlInsertionMark _insertionMark;
        private ContextMenuStrip _contextMenu;

        public SplitTabControl()
        {
            InitializeComponent();

            Initialize();
        }

        public SplitTabControl(IContainer container)
        {
            container.Add(this);

            InitializeComponent();

            Initialize();
        }

        private void Initialize()
        {
            _clickedIndex = -1;
            _clickdTab = null;
            _insertionMark = new TabControlInsertionMark(this);

            _contextMenu = new ContextMenuStrip();
            ContextMenuStrip = _contextMenu;
        }

        /// <summary>
        /// Split up current tab control into two tab controls.
        /// </summary>
        /// <param name="orientation">A value indicating the vertical or horizontal orientation of SplitPanel.</param>
        /// <param name="toFirst">The pages will be add to Panel1 after splitting.</param>
        /// <param name="tabPages">The pages which will be split.</param>
        public void Split(Orientation orientation, bool toFirst, params TabPage[] tabPages)
        {
            TabSplitContainer splitContainer = new TabSplitContainer();

            SplitterPanel panel1;
            SplitterPanel panel2;
            if (toFirst)
            {
                panel1 = splitContainer.Panel1;
                panel2 = splitContainer.Panel2;
            }
            else
            {
                panel1 = splitContainer.Panel2;
                panel2 = splitContainer.Panel1;
            }

            SplitTabControl subSplitTabControl1 = new SplitTabControl();
            SplitTabControl subSplitTabControl2 = new SplitTabControl();

            ControlManager.AddControl(panel1, subSplitTabControl1);
            ControlManager.AddControl(panel2, subSplitTabControl2);

            ControlManager.MoveTabPage(this.TabPages, subSplitTabControl1.TabPages, tabPages);
            ControlManager.MoveTabPage(this.TabPages, subSplitTabControl2.TabPages);

            Control parent = this.Parent;
            splitContainer.Orientation = orientation;
            splitContainer.Dock = DockStyle.Fill;
            parent.SuspendLayout();

            parent.Controls.Remove(this);
            parent.Controls.Add(splitContainer);
            parent.ResumeLayout();
        }

        /// <summary>
        /// Retrieves the tab that is located at the specified coordinates.
        /// </summary>
        /// <param name="position">A Point that contains the coordinates where you want to look for a tab.</param>
        /// <returns>The index of the tab that is located at the specified point.</returns>
        /// <remarks>If there is no tab at the specified point, the GetTabAtPosition method returns null.</remarks>
        private int GetTabAtPosition(Point position)
        {
            for (int i = 0; i < TabCount; i++)
            {
                Rectangle tabBound = GetTabRect(i);
                if (tabBound.Left <= position.X && tabBound.Right >= position.X && tabBound.Top <= position.Y && tabBound.Bottom >= position.Y)
                {
                    return i;
                }
            }
            return -1;
        }

        private void SplitTabControl_MouseDown(object sender, MouseEventArgs e)
        {
            _clickedIndex = GetTabAtPosition(e.Location);
            if (_clickedIndex != -1)
            {
                TabPage thePage = TabPages[_clickedIndex];
                if (thePage != null)
                {
                    _clickdTab = thePage;
                }
                else
                {
                    _clickdTab = null;
                }
            }
        }

        private void SplitTabControl_MouseMove(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left && _clickedIndex != -1)
            {
                DataObject dragdropData = new DataObject();
                dragdropData.SetData(this);
                dragdropData.SetData(_clickedIndex);
                dragdropData.SetData(_clickdTab);
                DoDragDrop(dragdropData, DragDropEffects.Move);
            }
        }

        private void SplitTabControl_DragOver(object sender, DragEventArgs e)
        {
            if (!e.Data.GetDataPresent(typeof(TabPage)))
            {
                e.Effect = DragDropEffects.None;
                return;
            }

            _insertionMark.InsertAtScreenPosition(new Point(e.X, e.Y));
            if (_insertionMark.Index != -1)
            {
                e.Effect = e.AllowedEffect;
            }
            else
            {
                e.Effect = DragDropEffects.None;
            }
        }

        private void SplitTabControl_DragEnter(object sender, DragEventArgs e)
        {
            
        }

        private void SplitTabControl_DragLeave(object sender, EventArgs e)
        {

        }

        private void SplitTabControl_DragDrop(object sender, DragEventArgs e)
        {
            if (!e.Data.GetDataPresent(typeof(TabPage)))
                return;

            int droppedIndex = _insertionMark.Index;
            if (droppedIndex == -1)
                return;

            int draggedIndex = (int)e.Data.GetData(typeof(Int32));
            TabPage draggedTabPage = (TabPage)e.Data.GetData(typeof(TabPage));
            TabControl draggedControl = (TabControl)e.Data.GetData(typeof(TabControl));

            if (draggedControl == this)
            {
                if (draggedIndex == droppedIndex)
                    return;

                if (_insertionMark.InsertAfterTab)
                {
                    if (draggedIndex > droppedIndex)
                    {
                        droppedIndex++;
                    }
                }
                else
                {
                    if (draggedIndex < droppedIndex)
                    {
                        droppedIndex--;
                    }
                }

                TabPages.RemoveAt(draggedIndex);
                TabPages.Insert(droppedIndex, draggedTabPage);
                SelectedIndex = droppedIndex;
            }
            else
            {
                if (_insertionMark.InsertAfterTab)
                {
                    droppedIndex++;
                }

                draggedControl.TabPages.RemoveAt(draggedIndex);
                TabPages.Insert(droppedIndex, draggedTabPage);
                SelectedIndex = droppedIndex;
            }
        }
    }
}
